////////////////////////////////////////////////////////////////////////////////
// This file is part of the Mist compiler.                                    //
//                                                                            //
// Copyright (C) 2009 The Mist project                                        //
//                                                                            //
// For a list of contributors, see the COMMITTERS file.                       //
//                                                                            //
// The Mist compiler is free software: you can redistribute it and/or modify  //
// it under the terms of the GNU General Public License as published by       //
// the Free Software Foundation, either version 3 of the License, or          //
// (at your option) any later version.                                        //
//                                                                            //
// The Mist compiler is distributed in the hope that it will be useful,       //
// but WITHOUT ANY WARRANTY; without even the implied warranty of             //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              //
// GNU General Public License for more details.                               //
//                                                                            //
// You should have received a copy of the GNU General Public License          //
// in the COPYING file. If not, see <http://www.gnu.org/licenses/>.           //
////////////////////////////////////////////////////////////////////////////////

///
/// \file
/// Contains the implementation of the Navigator methods.
///

#include "navigator.hpp"

////////////////////////////////////////////////////////////////////////////////
// Includes                                                                   //
////////////////////////////////////////////////////////////////////////////////

#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH

#include "visitor.hpp"
#include "tree.hpp"

////////////////////////////////////////////////////////////////////////////////
// Function Implementations                                                   //
////////////////////////////////////////////////////////////////////////////////

void Navigator::visit(wptr<Declarations> node) {
	assert(node);
	
	foreach (wptr<Declaration> d, node->declarations)
		d->accept(wptr_this());
}

void Navigator::visit(wptr<AssertionArea> node) {
	assert(node);
	
	foreach (wptr<Expression> d, node->conditions)
		d->accept(wptr_this());
}

void Navigator::visit(wptr<IfStatement> node) {
	assert(node);
	
	node->condition->accept(wptr_this());
	node->thenStatement->accept(wptr_this());
	if (node->elseStatement)
		node->elseStatement->accept(wptr_this());
}

void Navigator::visit(wptr<WhileStatement> node) {
	assert(node);
	
	node->condition->accept(wptr_this());
	
	foreach (wptr<AssertionArea> i, node->invariant)
		i->accept(wptr_this());
	
	foreach (wptr<Expression> b, node->bound)
		b->accept(wptr_this());
	
	foreach (wptr<CompoundStatement> s, node->statement)
		s->accept(wptr_this());
}

void Navigator::visit(wptr<ForStatement> node) {
	assert(node);
	
	node->iteratorType->accept(wptr_this());
	node->iterator    ->accept(wptr_this());
	node->collection  ->accept(wptr_this());
	
	foreach (wptr<AssertionArea> i, node->invariant)
		i->accept(wptr_this());
	
	foreach (wptr<CompoundStatement> s, node->statement)
		s->accept(wptr_this());
}

void Navigator::visit(wptr<CompoundStatement> node) {
	assert(node);
	
	if (node->name)
		node->name->accept(wptr_this());
	
	foreach (wptr<Statement> s, node->statements)
		s->accept(wptr_this());
}

void Navigator::visit(wptr<CppStatement> node) {
	assert(node);
}

void Navigator::visit(wptr<VariableDeclaration> node) {
	assert(node);
	
	node->type->accept(wptr_this());
	
	foreach (VariableDeclaration::Pair p, node->pairs) {
		p.name->accept(wptr_this());
		if (p.init)
			p.init->accept(wptr_this());
	}
}

void Navigator::visit(wptr<TypeDeclaration> node) {
	assert(node);
	
	node->name->accept(wptr_this());
}

void Navigator::visit(wptr<FunctionDeclaration> node) {
	assert(node);
	
	node->type->accept(wptr_this());
	node->name->accept(wptr_this());
	
	foreach (wptr<Identifier> pn, node->parameterNames)
		pn->accept(wptr_this());
	
	foreach (wptr<Identifier> ttn, node->templateTypeNames)
		ttn->accept(wptr_this());
	
	foreach (wptr<VariableDeclaration> lv, node->logicalVars)
		lv->accept(wptr_this());
	
	foreach (wptr<AssertionArea> pre, node->pre)
		pre->accept(wptr_this());
	
	foreach (wptr<AssertionArea> post, node->post)
		post->accept(wptr_this());
	
	foreach (wptr<Statement> body, node->body)
		body->accept(wptr_this());
}

void Navigator::visit(wptr<FunctionCall> node) {
	assert(node);
	
	node->base->accept(wptr_this());
	
	foreach (wptr<Expression> param, node->parameters)
		param->accept(wptr_this());
}

void Navigator::visit(wptr<OperatorCall> node) {
	assert(node);
	
	foreach (wptr<Expression> o, node->operands)
		o->accept(wptr_this());
}

void Navigator::visit(wptr<Reference> node) {
	assert(node);
	
	if (node->scopePart)
		node->scopePart->accept(wptr_this());
	
	if (node->formalTypeSpec) {
		foreach (wptr<Type> type, *node->formalTypeSpec)
			type->accept(wptr_this());
	}
	
	if (node->templateTypeSpec) {
		foreach (wptr<Type> type, *node->templateTypeSpec)
			type->accept(wptr_this());
	}
}

void Navigator::visit(wptr<BooleanLiteral> node) {
	assert(node);
}

void Navigator::visit(wptr<IntegerLiteral> node) {
	assert(node);
}

void Navigator::visit(wptr<ChainExpression> node) {
	assert(node);
	
	foreach (wptr<Expression> o, node->operands)
		o->accept(wptr_this());
}

void Navigator::visit(wptr<FunctionType> node) {
	assert(node);
	
	node->returnType->accept(wptr_this());
	
	foreach (wptr<Type> pt, node->parameterTypes)
		pt->accept(wptr_this());
}

void Navigator::visit(wptr<PointerType> node) {
	assert(node);
	
	node->type->accept(wptr_this());
}

void Navigator::visit(wptr<ArrayType> node) {
	assert(node);
	
	node->type->accept(wptr_this());
}

void Navigator::visit(wptr<NamedType> node) {
	assert(node);
	
	node->reference->accept(wptr_this());
}

void Navigator::visit(wptr<VoidType> node) {
	assert(node);
}

void Navigator::visit(wptr<TypeType> node) {
	assert(node);
}

void Navigator::visit(wptr<Identifier> node) {
	assert(node);
}
